home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / asm_n_z.zip / SIT.ASM < prev    next >
Assembly Source File  |  1989-10-23  |  18KB  |  652 lines

  1.     ;SIT -- enhanced SET for MS-DOS
  2.     ;
  3.     ;source code and executable placed IN THE PUBLIC DOMAIN by the author:
  4.     ;
  5.     ;  Davidson Corry
  6.     ;  4610 SW Lander
  7.     ;  Seattle, WA    98116
  8.     ;  (206) 935-0244
  9.     ;
  10.     ;support and enhancements are NOT guaranteed in any way, but
  11.     ;  if you have a question, suggestion, or comment, call me up.
  12.     ;  I might be tickled enough to do something about it!
  13.     ;
  14.     ;
  15.     ;Written for Microsoft MASM 5.1
  16.     ;
  17.     ;Use the following commands to create SIT.COM:
  18.     ;
  19.     ;    MASM SIT;
  20.     ;    LINK SIT;         (ignore the warning about NO STACK)
  21.     ;    EXE2BIN SIT
  22.     ;    REN SIT.BIN SIT.COM
  23.     ;
  24.     ;and then you can erase SIT.OBJ and SIT.EXE
  25.     ;
  26.     ;
  27.  
  28.     include    sit.inc ;structured ASM macros, etc.
  29.  
  30.  
  31.  
  32.     ;operation codes
  33. report    equ 1
  34. create    equ 2
  35. remove    equ 3
  36. append    equ 4
  37. prepend    equ 5
  38.  
  39. cseg    segment    byte public
  40.     assume    cs:cseg, ds:cseg, ss:cseg, es:nothing
  41.     ; CS = DS = ES = SS = PSP segment in .COM format programs
  42.  
  43.     org    100h ;.COM format executable
  44.  
  45. ;; ============= Primary routine
  46.  
  47. main:
  48.     call    locate_master_environment
  49.     call    clean_up_command_line
  50.     _if    <cmp byte ptr ds:[80h],0>,ne ;there ARE command line arguments
  51.         xor    cx,cx
  52.         mov    cl,ds:[80h]
  53.         inc    cx         ;copy command line INCLUDING terminating null
  54.         mov    ax,cs
  55.         mov    es,ax
  56.         mov    si,81h
  57.         mov    di,offset line_buffer
  58.         cld
  59.         rep    movsb
  60.         xor    ax,ax
  61.         stosb             ;terminate with a null
  62.         call    process_line
  63.     _else                 ;there are NO command line arguments, read lines from Standard Input
  64.         _while    <call read_from_stdin>,nc ;UNsuccessful read of a line from STDIN
  65.             call    process_line
  66.         _wend
  67.     _endif
  68.     mov    ax,4c00h         ;terminate program
  69.     dos
  70.  
  71. ;; ============== coded data
  72.  
  73.     public    master_env_seg, master_env_siz
  74.  
  75. master_env_seg    dw 0 ;segment address of master environment copy
  76. master_env_siz    dw 0 ;size (in bytes) of master environment copy
  77.  
  78.     public    variable_size, variable_posn
  79.  
  80. variable_size    dw 0 ;size (in bytes) of resultant VARIABLE=VALUE string
  81. variable_posn    dw 0 ;position (in master environment area) to replace new VARIABLE=VALUE string
  82.  
  83.     public    variable_name_size
  84.  
  85. variable_name_size    dw 0
  86.  
  87.     public    operation
  88.  
  89. operation    db 0 ;which op to perform? remove, change, append, prepend, report?
  90.  
  91.     public    no_room_msg
  92. no_room_msg    db 'Master environment allocation exceeded$'
  93.  
  94.     public    bad_syntax_msg
  95. bad_syntax_msg    db 'Bad syntax.  Usage is VARIABLE { [ | = | += | -= | &= ] VALUE STRING }$'
  96.  
  97.     public    cant_find_command_com_msg
  98. cant_find_command_com_msg    db    'Cannot locate primary command shell, terminating.$'
  99.  
  100.     public    cant_find_master_env_msg
  101. cant_find_master_env_msg       db      'Cannot locate master environment segment, terminating.',cr,lf
  102.     db    '  If you are using 4DOS, you must use the /M:nnn switch -- see 4DOS.DOC$'
  103.  
  104. ;; ============== support routines
  105.  
  106.     public    clean_up_command_line
  107. clean_up_command_line:
  108.     xor    cx,cx
  109.     mov    cl,ds:[80h]         ;CX = size of command line passed to SIT
  110.     xor    dx,dx             ;clear bitflags 01 = "there were nonblank characters"
  111.     mov    si,81h
  112.     _if    ,ncxz             ;if there are some chars on command line...
  113.         _loop
  114.             _if    <cmp byte ptr [si],' '>,a
  115.                 or    dx,01 ;there are nonblank characters in the command line
  116.             _endif
  117.             inc    si
  118.         _nextcx
  119.     _endif
  120.     _if    <test dx,1>,z         ;there were NO non-blank characters in command line, kill command line
  121.         mov    byte ptr ds:[80h],0 ;pretend the command line was empty
  122.     _endif
  123.     mov    si,81h
  124.     xor    bx,bx
  125.     mov    bl,ds:[80h]
  126.     mov    byte ptr [bx+si],0     ;null-terminate command line
  127.     ret
  128.  
  129.     public    read_from_stdin
  130. read_from_stdin:
  131.     mov    dx,offset line_buffer
  132.     _loop
  133.         mov    ah,3fh         ;"read from file handle"
  134.         mov    bx,0         ;STDIN file handle, always open
  135.         mov    cx,1         ;get 1 character
  136.         dos
  137.     _break    <test ax,ax>,z         ;no characters read, we're at end-of-file
  138.         mov    si,dx
  139.     _break    <cmp byte ptr [si],'Z'-'@'>,e ;ctrl-Z is end-of-file too!
  140.  
  141.         ;Input from STDIN may have lines delimited by
  142.         ; CR alone, LF alone, CR/LF or LF/CR (depending on
  143.         ; whether the source is the keyboard or a text file
  144.         ; from any of several kinds of editors.
  145.         ;To handle the re-display consistently, we
  146.         ; 1) treat CR and LF identically
  147.         ; 2) treat CR (or LF) as an end-of-line marker
  148.         ;      ONLY when there are characters in the line buffer,
  149.         ;    otherwise ignore it.
  150.         ; 3) echo all characters up to EOL, then explicitly send
  151.         ;      a CR/LF
  152.  
  153.         _if    <cmp byte ptr [si],lf>,e ;treat LF = CR
  154.             mov    byte ptr [si],cr
  155.         _endif
  156.  
  157.         _if    <cmp byte ptr [si],cr>,e ;possible end-of-line
  158.     _again    <cmp dx,offset line_buffer>,e ;no chars in buffer, ignore CR
  159.             mov    byte ptr [si],0 ;terminate line with null
  160.     _break
  161.         _endif
  162.         inc    dx
  163.     _lend
  164.     ;read from STDIN reached end-of-file or end-of-line, return CARRY if buffer is empty
  165.     _if    <cmp dx,offset line_buffer>,e ;no chars
  166.         stc             ;set CARRY = unsuccessful read
  167.     _else
  168.         clc
  169.     _endif
  170.     ret
  171.  
  172.     public    locate_master_environment
  173. locate_master_environment:
  174.     ;locate master copy of environment
  175.  
  176.     ;first step is to locate the master copy of COMMAND.COM
  177.     ; (or whatever command shell is in charge)
  178.     ;This is the first memory block that "owns itself" --
  179.     ; that is, the segment of the arena header is one less than
  180.     ; the segment of the PSP that owns it
  181.  
  182.     ;see Ray Duncan's ADVANCED MS-DOS for an excellent discussion
  183.     ; of memory allocation and arena headers in MS-DOS
  184.  
  185.     ;NOTE *** in version 1.0 of SIT, I assumed that the segment portion of
  186.     ;    the INT 2Eh vector pointed to the master COMMAND.COM segment --
  187.     ;    that turned out to be true for Microsoft COMMAND.COM, but
  188.     ;    not for the (excellent) shareware replacement 4DOS --
  189.     ; The following method is more robust, and correctly finds both
  190.     ;    COMMAND.COM and 4DOS.
  191.  
  192.     mov    ah,52h
  193.     dos                 ;undocumented DOS call, returns ES:BX -> "list of lists"
  194.     mov    ax,es:-2[bx]         ;BX is the segment address of the first DOS memory allocation block
  195.     push    ax             ;save the pointer to the first memory block
  196.     _loop
  197.         mov    es,ax         ;ES -> segaddr of arena header
  198.         inc    ax         ;AX -> segaddr of memory block itself
  199.         cmp    ax,es:[1]     ;see if they're the same
  200.         _if    ,e         ;yes, they're the same, AX is the segaddr of the primary shell COMMAND.COM
  201.             mov    di,ax     ;save it in AX for next loop
  202.     _break
  203.         _endif
  204.         _if    <cmp    byte ptr es:[0],'Z'>,e    ;reached end of arena header chain, COMMAND.COM not found (impossible, but true...)
  205.             mov    dx,offset cant_find_command_com_msg
  206.             mov    ah,9
  207.             dos
  208.             mov    ax,4cffh    ;quit with errorlevel 255
  209.             dos
  210.         _endif
  211.         add    ax,es:[3]     ;advance AX -> next arena header
  212.     _lend
  213.     pop    ax             ;restore segment address of first memory block
  214.  
  215.     _loop
  216.         mov    es,ax         ;ES segment is a memory allocation block ("arena header")
  217.  
  218.         ;see who "owns" this block of memory -- the PSP segment
  219.         ; of the owner is the value in the word at ES:[1]
  220.  
  221.         _if    <cmp di,es:[1]>,e ;master COMMAND.COM owns it, see if it's the master environment
  222.             _if    <cmp word ptr es:[3],3>,a ;3-paragraph block is the CURRENTLY-RUNNING PROGRAM block
  223.                 inc    ax ;AX is segment address of memory block ITSELF (rather than its arena header)
  224.                 cmp    di,ax ;compare to COMMAND.COM PSP segment value
  225.                 mov    ax,es ;restore AX -> arena header, but doesn't affect flags from CMP DI,BX
  226.  
  227.                 ;The first three memory blocks owned by the master copy of COMMAND.COM are usually
  228.                 ;  1) COMMAND.COM itself,
  229.                 ;  2) a 48-byte block containing the name of the
  230.                 ;    currently-executing program, and
  231.                 ;  3) the master environment block
  232.                 ;
  233.                 ;We can tell them apart because the arena header for COMMAND.COM will be
  234.                 ;  immediately preceding the memory block for COMMAND.COM (segment pointed by DI),
  235.                 ;  while the arena header for the master environment strings block will
  236.                 ;  be somewhere else.
  237.                 _if    ,ne ;arena header did NOT immediately precede the DI segment, we've found master environment block
  238.                     inc    ax ;AX -> segment of environment block
  239.                     mov    master_env_seg,ax
  240.                     mov    ax,es:[3] ;size of memory block in paragraphs
  241.                     shl    ax,1
  242.                     shl    ax,1
  243.                     shl    ax,1
  244.                     shl    ax,1 ;AX = size of memory block in BYTES
  245.                     mov    master_env_siz,ax
  246.                     mov    ax,cs
  247.                     mov    es,ax ;restore ES = local segment
  248.                     ret ;done, return to main routine
  249.